/*
 *  Copyright (C) 2010 Glauco
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.balisunrise.annotation.util;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import org.balisunrise.annotation.VisualEntity;
import org.balisunrise.annotation.Panel;
import org.balisunrise.annotation.PanelType;

/**
 * Esta classe contém os atributos para construção de um painel de uma entidade.
 *
 * @author Glauco
 */
public class PanelUtilities extends VisualEntityUtilities{

    private static final String MESSAGE = "Erro ao ler Annotation \"Panel\".";

    /**
     * Quantidade de atributos mostrados no painel.
     * No caso do tipo do painel não ser SINGLE, este valore representa o
     * número de paineis associados.
     */
    public int length;

    /**
     * Tipo do painel.
     */
    public PanelType type;

    /**
     * Nome dos paineis associados a este.
     */
    public String[] associatedPanels;

    /**
     * Campos dos painel.
     */
    public List<FieldUtilities> fields;

    /**
     * painéis associados.
     */
    public List<PanelUtilities> associatedPanelsUtilities;

    /**
     * Cria novo PanelUtitlities.
     */
    public PanelUtilities(){
        fields = new ArrayList<FieldUtilities>();
        associatedPanelsUtilities = new ArrayList<PanelUtilities>();
    }

    /**
     * Lê a annotation Panel com o alias da VisualEntity.
     * @param entityClass Classe para ler.
     * @param alias alias da Panel.
     * @return a annotation Panel do alias.
     * @throws AnnotationsUtilitiesException Caso não encontre.
     */
    public static Panel readPanelAnnotation(
            Class entityClass, String alias) throws AnnotationsUtilitiesException {

        if (entityClass == null)
            throw new AnnotationsUtilitiesException( MESSAGE +
                    "\nParâmentro \"entityClass\" não pode ser nulo!");

        if (alias == null)
            throw new AnnotationsUtilitiesException( MESSAGE +
                    "\nParâmentro \"alias\" não pode ser nulo!");

        VisualEntity ve = readVisualEntityAnnotation(entityClass);
        for (int i = 0; i < ve.panels().length; i++) {
            Panel panel = ve.panels()[i];
            for (int j = 0; j < panel.alias().length; j++) {
                if (panel.alias()[j].equals(alias))
                    return panel;
            }
        }

        throw new AnnotationsUtilitiesException( MESSAGE +
                "\nAnnotation \"Panel\" não encontrada para o " +
                "nome\""+ alias +"\"!");
    }

    /**
     * Le a annotation Panel e cria um PanelUtilities a parir dos dados da
     * annotation.
     *
     * @param entityClass Classe para ler.
     * @param alias alias da Panel.
     * @return PanelUtilities
     * @throws AnnotationsUtilitiesException Caso não encontre a annotation ou
     * algum parâmetro seja nulo.
     */
    public static PanelUtilities create(Class entityClass, String alias)
            throws AnnotationsUtilitiesException {

        if (entityClass == null)
            throw new AnnotationsUtilitiesException( MESSAGE +
                    "\nParâmentro \"entityClass\" não pode ser nulo!");

        if (alias == null)
            throw new AnnotationsUtilitiesException( MESSAGE +
                    "\nParâmentro \"alias\" não pode ser nulo!");

        Panel p = readPanelAnnotation(entityClass, alias);

        PanelUtilities pu = new PanelUtilities();
        pu.entityClass = entityClass;
        pu.alias = alias;
        pu.title = p.title();
        pu.associatedPanels = p.associatedPanels();
        pu.type = p.type();

        if(pu.type != PanelType.SINGLE){
            for (String panel : pu.associatedPanels) {
                pu.associatedPanelsUtilities.add(
                        PanelUtilities.create(entityClass, panel));
            }
            // conta número de campos
            pu.length = pu.associatedPanelsUtilities.size();
        }else{
            // cria os campos
            ReflectUtilities ru = new ReflectUtilities(entityClass);
            for (Field field : ru.getDeclaredFields()) {
            //for (Field field : entityClass.getDeclaredFields()) {
                try{
                    pu.fields.add(FieldUtilities.create(field, alias));
                }catch(AnnotationsUtilitiesException aue){
                    // Não importa se ocorreu exceção,
                    // apenas não inclui o campo na lista.
                }
            }
            // ordena
            FieldUtilities.sort(pu.fields);
            // verifica os campos embedded e selection
            for (FieldUtilities pfu : pu.fields) {
                if(pfu.type != FieldUtilities.DEFINITION){
                    PanelUtilities puAux = create(pfu.field.getType(), pfu.call);
                    pfu.embedded = puAux.fields;
                }
            }
            // conta número de campos
            pu.length = 0;
            for (FieldUtilities pfu : pu.fields) {
                pu.length += pfu.count();
            }
        }

        return pu;
    }
}
